#ifndef BFCP_TRANSPORT_INTERFACE_HXX
#define BFCP_TRANSPORT_INTERFACE_HXX

#include "BfcpNetTuple.hxx"
#include "BfcpSendData.hxx"
#include "BfcpTransactionMessage.hxx"
#include "rutil/ProducerFifoBuffer.hxx"
#include "rutil/ConsumerFifoBuffer.hxx"
#include "rutil/TransportType.hxx"
#include "rutil/FdSetIOObserver.hxx"
#include "rutil/BaseException.hxx"
#include "rutil/FdPoll.hxx"
#include "rutil/Data.hxx"


namespace bfcp {

    class BfcpMessage;

    class BfcpTransportIf : public resip::FdSetIOObserver
    {
    public:
        /**
             @brief General exception class for Transport.

             This would be thrown if there was an attempt to bind to a port
             that is already in use.
          */
        class Exception : public resip::BaseException
        {
        public:
            Exception(const resip::Data& msg, const resip::Data& file, const int line);
            const char* name() const { return "TransportException"; }
        };

        BfcpTransportIf(const resip::Data& intfc,
                        int portNum,
                        resip::IpVersion version,
                        resip::Fifo<BfcpTransactionMessage>& rxFifo);
        virtual ~BfcpTransportIf();

        virtual void buildFdSet(resip::FdSet& fdset) {}
        virtual unsigned int getTimeTillNextProcessMS() { return UINT_MAX; }
        virtual void process(resip::FdSet& fdset) {}

        virtual bool isFinished() const;
        virtual bool hasDataToSend() const;

        const resip::TransportType transport() const { return mTuple.getType(); }

        virtual void send(std::auto_ptr<BfcpSendData> data);

        /**
         Version of process to be invoked periodically when using callback-based
         IO (via FdPollGrp).
        */
        virtual void process() = 0;

        virtual void setPollGrp(resip::FdPollGrp *grp);

        virtual void shutdown() { mShuttingDown = true; }
        virtual bool isShuttingDown() { return mShuttingDown; }

        // called by Connection to deliver a received message
        virtual void pushRxMsgUp(BfcpMessage* msg);

        // set the receive buffer length (SO_RCVBUF)
        virtual void setRcvBufLen(int buflen) { };	// make pure?

        static resip::Socket socket(resip::TransportType type, resip::IpVersion ipVer);
        void bind();
        static void error(int e);

        int getPort() const { return mTuple.getPort(); }
        const BfcpNetTuple& getTuple() const { return mTuple; }

    protected:
        bool mShuttingDown;
        resip::Socket mFd; // this is a unix file descriptor or a windows SOCKET
        BfcpNetTuple mTuple;
        resip::ProducerFifoBuffer<BfcpTransactionMessage> mStateMachineFifo; // passed in
        resip::Fifo<BfcpSendData> mTxFifo; // owned by the transport
        resip::ConsumerFifoBuffer<BfcpSendData> mTxFifoOutBuffer;
        resip::FdPollGrp *mPollGrp;      // not owned by transport, just used
        resip::FdPollItemHandle mPollItemHandle; // owned by the transport
    };

}

#endif // #ifndef BFCP_TRANSPORT_INTERFACE_HXX
